﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using ORM.Annotations;
using Domain.Commons;

namespace DBUtils
{
    internal class SqlDBWrapper : DBWrapper
    {
        public override IDbConnection CreateConnection()
        {
            if (String.IsNullOrEmpty(DBConnectionString))
            {
                throw new NullReferenceException("Get the connection string from system configuration is null.");
            }
            
            return new SqlConnection(DBConnectionString);
        }

        public override T Get<T>(object id)
        {
            IORMAnalyzer analyzer = new ORMAnalyzer(typeof(T));
            if (null == analyzer.PrimaryKey)
            {
                throw new ORMAnalyzerException("Entity has not define primary key : " + typeof(T).Name);
            }

            StringBuilder sqlBuilder = GetSelectBaseSql(analyzer);
            sqlBuilder.Append(" where ").Append(analyzer.PrimaryKey.Name).Append(" = @id");
            using (IDataReader reader = this.Query(sqlBuilder.ToString(), new SqlParameter("@id", id)))
            {
                if (null != reader)
                {
                    return BuildInstanceByORM<T>(reader, analyzer);
                }
            }

            return null;
        }


        public override int Insert(object entity)
        {
            IORMAnalyzer analyzer = new ORMAnalyzer(entity.GetType());
            if (null == analyzer.PrimaryKey)
            {
                throw new ORMAnalyzerException("Entity has not define primary key : " + entity.GetType().Name);
            }
            StringBuilder insertPart = new StringBuilder();
            StringBuilder valuesPart = new StringBuilder();
            List<SqlParameter> parameters = new List<SqlParameter>();
            foreach (EntityFeild feild in analyzer.FeildInfoes)
            {
                if (insertPart.Length == 0)
                {
                    insertPart.Append(feild.Name);
                }
                else
                {
                    insertPart.Append(",").Append(feild.Name);
                }
                if (valuesPart.Length == 0)
                {
                    valuesPart.Append("@" + feild.Name);
                }
                else
                {
                    valuesPart.Append(",").Append("@" + feild.Name);
                }
                parameters.Add(new SqlParameter("@" + feild.Name, feild.FeildRefInfo.GetValue(entity, null)));
            }
            StringBuilder sqlBuild = new StringBuilder("Insert ").Append(analyzer.TableInfo.Name).Append("(")
                .Append(insertPart.ToString()).Append(") values (").Append(valuesPart.ToString()).Append(")");
            return ExecuteNonQuery(sqlBuild.ToString(), parameters.ToArray());
        }

        public override int Update(object entity)
        {
            IORMAnalyzer analyzer = new ORMAnalyzer(entity.GetType());
            if (null == analyzer.PrimaryKey)
            {
                throw new ORMAnalyzerException("Entity has not define primary key : " + entity.GetType().Name);
            }
            StringBuilder mainbuilder = new StringBuilder();
            List<SqlParameter> parameters = new List<SqlParameter>();
            foreach (EntityFeild feild in analyzer.FeildInfoes)
            {
                if (null != analyzer.PrimaryKey && analyzer.PrimaryKey.Equals(feild))
                {
                    continue;
                }
                if (mainbuilder.Length == 0)
                {
                    mainbuilder.Append(feild.Name).Append(" = ").Append("@" + feild.Name);
                }
                else
                {
                    mainbuilder.Append(",").Append(feild.Name).Append(" = ").Append("@" + feild.Name);
                }
                parameters.Add(new SqlParameter("@" + feild.Name, feild.FeildRefInfo.GetValue(entity, null)));
            }
            StringBuilder sqlbuilder = new StringBuilder("Update " + analyzer.TableInfo.Name).Append(" Set ")
                .Append(mainbuilder.ToString()).Append(" Where ").Append(analyzer.PrimaryKey.Name).Append(" = @" + analyzer.PrimaryKey.Name);
            parameters.Add(new SqlParameter("@" + analyzer.PrimaryKey.Name, analyzer.PrimaryKey.FeildRefInfo.GetValue(entity, null)));
            return ExecuteNonQuery(sqlbuilder.ToString(), parameters.ToArray());
        }

        public override int Delete(object entity)
        {
            IORMAnalyzer analyzer = new ORMAnalyzer(entity.GetType());
            if (null == analyzer.PrimaryKey)
            {
                throw new ORMAnalyzerException("Entity has not define primary key : " + entity.GetType().Name);
            }
            return Delete(analyzer, analyzer.PrimaryKey.FeildRefInfo.GetValue(entity, null));
        }

        public override int Delete<T>(object id)
        {
            IORMAnalyzer analyzer = new ORMAnalyzer(typeof(T));
            if (null == analyzer.PrimaryKey)
            {
                throw new ORMAnalyzerException("Entity has not define primary key : " + typeof(T).Name);
            }
            return Delete(analyzer, id);
        }

        protected int Delete(IORMAnalyzer analyzer, object id)
        {
            StringBuilder sqlbuilder = new StringBuilder("Delete From ").Append(analyzer.TableInfo.Name)
                .Append(" Where ").Append(analyzer.PrimaryKey.Name)
                .Append(" = @" + analyzer.PrimaryKey.Name);
            return ExecuteNonQuery(sqlbuilder.ToString(), new SqlParameter("@" + analyzer.PrimaryKey.Name, id));
        }
    }
}
